Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

VisualizeSourceData.m 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. function varargout = VisualizeSourceData(varargin)
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. % Visualization HUB for source analysis data. %
  4. % Last modified: Feb.26, 2014 %
  5. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  6. %
  7. % Usage:
  8. % VisualizeSourceData(BuilderMatFile)
  9. %
  10. % Inputs:
  11. % BuilderMatFile = Can be empty or specify target Builder .mat file.
  12. % Copyright (C) 2013-2014, Michael J. Cheung
  13. %
  14. % This file is a part of the MEG & PLS Pipeline (MEGPLS). For more
  15. % details, see the documentation included with the software package.
  16. %
  17. % MEGPLS is free software: you can redistribute it and/or modify it under
  18. % the terms of the GNU General Public License version 2 as published by
  19. % the Free Software Foundation. This program is distributed in the hope
  20. % that it will be useful, but WITHOUT ANY WARRANTY; without even the
  21. % implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  22. % See the GNU General Public License for more details.
  23. %
  24. % You should have received a copy of the GNU General Public License along
  25. % with this program. If not, you can download the license here:
  26. % <http://www.gnu.org/licenses/old-licenses/gpl-2.0>.
  27. % Last Modified by GUIDE v2.5 16-Sep-2014 11:25:43
  28. % Begin initialization code - DO NOT EDIT
  29. gui_Singleton = 1;
  30. gui_State = struct('gui_Name', mfilename, ...
  31. 'gui_Singleton', gui_Singleton, ...
  32. 'gui_OpeningFcn', @VisualizeSourceData_OpeningFcn, ...
  33. 'gui_OutputFcn', @VisualizeSourceData_OutputFcn, ...
  34. 'gui_LayoutFcn', [] , ...
  35. 'gui_Callback', []);
  36. if nargin && ischar(varargin{1})
  37. gui_State.gui_Callback = str2func(varargin{1});
  38. end
  39. if nargout
  40. [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
  41. else
  42. gui_mainfcn(gui_State, varargin{:});
  43. end
  44. % End initialization code - DO NOT EDIT
  45. %--- Executes just before VisualizeSourceData is made visible. ---%
  46. %-------------------------------------------------------%
  47. function VisualizeSourceData_OpeningFcn(hObject, eventdata, handles, varargin)
  48. % This function has no output args, see OutputFcn.
  49. % hObject handle to figure
  50. % eventdata reserved - to be defined in a future version of MATLAB
  51. % handles structure with handles and user data (see GUIDATA)
  52. % varargin command line arguments to VisualizeSourceData (see VARARGIN)
  53. % Choose default command line output for VisualizeSourceData
  54. handles.output = hObject;
  55. % Make sure toolbox paths are added:
  56. [PipelineDir, ~, ~] = fileparts(which('VisualizeSourceData.m'));
  57. addpath(genpath(PipelineDir));
  58. rmpath([PipelineDir,'/DEFAULT_SETTINGS']); % Make sure its calling from AnalysisID
  59. rmpath([PipelineDir,'/TEMPORARY_FIXES']); % Make sure its calling from FT toolbox
  60. CheckToolboxPaths(PipelineDir);
  61. % Initialize variables and default settings:
  62. handles.name.GroupID = [];
  63. handles.name.SubjID = [];
  64. handles.name.CondID = [];
  65. handles.paths = [];
  66. handles.gui.SubjIDAvgList = []; % SubjID list with GrpAvg at end of list.
  67. handles.gui.FuncOverlayFile = [];
  68. handles.gui.FuncDisplayPath = [];
  69. handles.gui.FuncOverlayLegend = [];
  70. handles.gui.AnatUnderlayFile = [];
  71. handles.gui.TempViewFolder = [];
  72. handles.gui.GrpAvgUnderlay = ... % Default AnatUnderlay file for GrpAvg func images.
  73. [PipelineDir,'/MEGPLS_TOOLBOX/Masks_Templates/template_ch2+tlrc.BRIK'];
  74. handles.gui.PlotOverlap = 'no'; % For legend construction
  75. handles.gui.PlotGrpAvg = 'no';
  76. % Check for BuilderMat input:
  77. if isempty(varargin)
  78. handles.gui.BuilderMat = [];
  79. elseif numel(varargin) > 1
  80. disp('Error: Input should be empty or a Builder .mat file.')
  81. error('Incorrect number of inputs.')
  82. elseif exist(varargin{1}, 'file')
  83. handles.gui.BuilderMat = varargin{1};
  84. handles = LoadBuilderMat(handles, varargin{1});
  85. end
  86. % Update handles structure
  87. guidata(hObject, handles);
  88. % UIWAIT makes VisualizeSourceData wait for user response (see UIRESUME)
  89. % uiwait(handles.figure1);
  90. %--- Outputs from this function are returned to the command line. ---%
  91. %--------------------------------------------------------------------%
  92. function varargout = VisualizeSourceData_OutputFcn(hObject, eventdata, handles)
  93. % varargout cell array for returning output args (see VARARGOUT);
  94. % hObject handle to figure
  95. % eventdata reserved - to be defined in a future version of MATLAB
  96. % handles structure with handles and user data (see GUIDATA)
  97. % Get default command line output from handles structure
  98. varargout{1} = handles.output;
  99. %=====================================%
  100. % FUNCTIONS FOR LOADING BUILDER .MAT: %
  101. %=====================================%
  102. %--- Textbox to display selected path of Builder: ---%
  103. %----------------------------------------------------%
  104. function TextboxBuilderMat_Callback(hObject, eventdata, handles)
  105. EnteredText = get(handles.TextboxBuilderMat, 'String');
  106. if ~isequal(EnteredText, handles.gui.BuilderMat)
  107. set(handles.TextboxBuilderMat, 'String', handles.gui.BuilderMat);
  108. msgbox('Note: Use the button to change Builder .mat file.')
  109. end
  110. %--- Executes on button press in ButtonLoadBuilderMat. ---%
  111. %---------------------------------------------------------%
  112. function ButtonLoadBuilderMat_Callback(hObject, eventdata, handles)
  113. [BuilderFile, BuilderPath] = uigetfile('Builder_*.mat',...
  114. 'Select Builder .mat file to load:', 'MultiSelect', 'off');
  115. if BuilderFile == 0
  116. return; % If user cancels
  117. else
  118. handles.gui.BuilderMat = [BuilderPath,BuilderFile];
  119. set(handles.TextboxBuilderMat, 'String', handles.gui.BuilderMat);
  120. handles = LoadBuilderMat(handles, handles.gui.BuilderMat);
  121. guidata(hObject, handles);
  122. end
  123. %--- Loads variables from Builder .mat file. ---%
  124. %-----------------------------------------------%
  125. function OutputHandles = LoadBuilderMat(InputHandles, BuilderMat)
  126. handles = InputHandles;
  127. % Reset variables to default:
  128. handles.name.GroupID = [];
  129. handles.name.SubjID = [];
  130. handles.name.CondID = [];
  131. handles.paths = [];
  132. handles.gui.SubjIDAvgList = []; % SubjID list with GrpAvg at end of list.
  133. handles.gui.TempViewFolder = [];
  134. handles.gui.AnatUnderlayFile = [];
  135. handles.gui.FuncOverlayFile = [];
  136. handles.gui.FuncOverlayLegend = [];
  137. handles.gui.FuncDisplayPath = [];
  138. set(handles.TextboxFuncImageFile, 'String', []);
  139. [PipelineDir, ~, ~] = fileparts(which('VisualizeSourceData.m'));
  140. handles.gui.GrpAvgUnderlay = ... % Default AnatUnderlay file for GrpAvg func images.
  141. [PipelineDir,'/MEGPLS_TOOLBOX/Masks_Templates/template_ch2+tlrc.BRIK'];
  142. handles.gui.PlotOverlap = 'no'; % For legend construction
  143. handles.gui.PlotGrpAvg = 'no';
  144. % Load Builder .mat:
  145. LoadBuilder = load(BuilderMat);
  146. handles.name = LoadBuilder.name;
  147. handles.paths = LoadBuilder.paths;
  148. % Update GUI:
  149. GroupIndex = get(handles.ListboxGroupID, 'Value');
  150. set(handles.ListboxSubjID, 'Value', length(handles.name.SubjID{GroupIndex})+1);
  151. handles = UpdateNameIDs(handles);
  152. set(handles.TextboxBuilderMat, 'String', handles.gui.BuilderMat);
  153. % Set output handles:
  154. OutputHandles = handles;
  155. %============================%
  156. % FUNCTIONS FOR ID DISPLAYS: %
  157. %============================%
  158. %--- Executes on selection change in ListboxGroupID. ---%
  159. %-------------------------------------------------------%
  160. function ListboxGroupID_Callback(hObject, eventdata, handles)
  161. handles = UpdateNameIDs(handles);
  162. guidata(hObject, handles);
  163. %--- Executes on selection change in ListboxSubjID. ---%
  164. %------------------------------------------------------%
  165. function ListboxSubjID_Callback(hObject, eventdata, handles)
  166. handles = UpdateNameIDs(handles);
  167. guidata(hObject, handles);
  168. %--- Executes on selection change in ListboxCondID. ---%
  169. %------------------------------------------------------%
  170. function ListboxCondID_Callback(hObject, eventdata, handles)
  171. handles = UpdateNameIDs(handles);
  172. guidata(hObject, handles);
  173. %--- Update GroupID's, SubjID's, and CondID's: ---%
  174. %-------------------------------------------------%
  175. function OutputHandles = UpdateNameIDs(InputHandles)
  176. handles = InputHandles;
  177. % Update GroupID listbox:
  178. set(handles.ListboxGroupID, 'String', handles.name.GroupID);
  179. GroupIndex = get(handles.ListboxGroupID, 'Value');
  180. MaxGroupIndex = length(handles.name.GroupID);
  181. if isempty(GroupIndex) || GroupIndex == 0 || GroupIndex > MaxGroupIndex
  182. set(handles.ListboxGroupID, 'Value', MaxGroupIndex);
  183. end
  184. % Update SubjID listbox:
  185. % Note: Group-averages do not exist for raw sources.
  186. if isempty(handles.name.SubjID)
  187. set(handles.ListboxSubjID, 'String', []);
  188. MaxSubjIndex = 0;
  189. elseif get(handles.ButtonViewRawSources, 'Value') == 1 % Raw sources do not have GPAVG.
  190. set(handles.ListboxSubjID, 'String', handles.name.SubjID{GroupIndex});
  191. MaxSubjIndex = length(handles.name.SubjID{GroupIndex});
  192. elseif get(handles.ButtonViewNormSources, 'Value') == 1 % Add NormSource GPAVG to list.
  193. handles.gui.SubjIDAvgList{GroupIndex} = [handles.name.SubjID{GroupIndex}; 'GroupAvg'];
  194. set(handles.ListboxSubjID, 'String', handles.gui.SubjIDAvgList{GroupIndex});
  195. MaxSubjIndex = length(handles.gui.SubjIDAvgList{GroupIndex});
  196. end
  197. SubjIndices = get(handles.ListboxSubjID, 'Value');
  198. if isempty(SubjIndices) || max(SubjIndices) == 0 || max(SubjIndices) > MaxSubjIndex
  199. set(handles.ListboxSubjID, 'Value', MaxSubjIndex);
  200. end
  201. % Update CondID listbox:
  202. set(handles.ListboxCondID, 'String', handles.name.CondID);
  203. CondIndices = get(handles.ListboxCondID, 'Value');
  204. MaxCondIndex = length(handles.name.CondID);
  205. if isempty(CondIndices) || max(CondIndices) == 0 || max(CondIndices) > MaxCondIndex
  206. set(handles.ListboxCondID, 'Value', MaxCondIndex);
  207. end
  208. % Check SubjID & CondID multi-selection:
  209. % For raw sources, allow only multiple CondID selection for voxel timeseries plots.
  210. % Cannot overlay SubjIDs for raw sources since each subject is in its own space.
  211. if get(handles.ButtonViewRawSources, 'Value') == 1
  212. if length(SubjIndices) > 1
  213. SubjIndices = 1;
  214. set(handles.ListboxSubjID, 'Value', 1);
  215. end
  216. end
  217. if length(SubjIndices) == 1 && length(CondIndices) == 1
  218. handles.gui.PlotOverlap = 'no';
  219. elseif length(SubjIndices) > 1 && length(CondIndices) == 1
  220. handles.gui.PlotOverlap = 'SubjIDs';
  221. elseif length(SubjIndices) == 1 && length(CondIndices) > 1
  222. handles.gui.PlotOverlap = 'CondIDs';
  223. elseif length(SubjIndices) > 1 && length(CondIndices) > 1
  224. handles.gui.PlotOverlap = 'Both';
  225. end
  226. % Check if GroupAvg is selected:
  227. if get(handles.ButtonViewRawSources, 'Value') == 1 || isempty(handles.gui.SubjIDAvgList)
  228. handles.gui.PlotGrpAvg = 'no';
  229. else
  230. GroupIndex = get(handles.ListboxGroupID, 'Value');
  231. GrpAvgIndex = length(handles.gui.SubjIDAvgList{GroupIndex});
  232. if ismember(GrpAvgIndex, SubjIndices)
  233. handles.gui.PlotGrpAvg = 'yes';
  234. else
  235. handles.gui.PlotGrpAvg = 'no';
  236. end
  237. end
  238. % Set output handles:
  239. OutputHandles = handles;
  240. %=========================================================%
  241. % FUNCTIONS FOR FUNCTIONAL OVERLAY & ANATOMICAL UNDERLAY: %
  242. %=========================================================%
  243. %--- Executes on button press in ButtonSetFuncOverlay. ---%
  244. %---------------------------------------------------------%
  245. function ButtonSetFuncOverlay_Callback(hObject, eventdata, handles)
  246. if isempty(handles.gui.BuilderMat)
  247. msgbox('Warning: Select Builder .mat file first.', 'Warning:');
  248. return;
  249. end
  250. % Make sure selection parameters updated:
  251. handles = UpdateNameIDs(handles);
  252. % Get selected indices:
  253. g = get(handles.ListboxGroupID, 'Value');
  254. s = get(handles.ListboxSubjID, 'Value');
  255. c = get(handles.ListboxCondID, 'Value');
  256. if length(s) > 1 || length(c) > 1
  257. msgbox('Warning: Only one image file can be set as the functional overlay.');
  258. return;
  259. end
  260. % Acquire dataset paths for functional & anatomical image:
  261. if get(handles.ButtonViewRawSources, 'Value') == 1
  262. FuncOverlay = handles.paths.Afni4DSource{g}{s,c};
  263. AnatUnderlay = handles.paths.MRIdataAfni{g}{s};
  264. elseif get(handles.ButtonViewNormSources, 'Value') == 1
  265. if strcmp(handles.gui.PlotGrpAvg, 'no')
  266. FuncOverlay = handles.paths.Afni4DNormSource{g}{s,c};
  267. AnatUnderlay = handles.paths.NormMRIAfni{g}{s};
  268. else
  269. FuncOverlay = handles.paths.Afni4DGrpAvg{g}{c};
  270. AnatUnderlay = handles.gui.GrpAvgUnderlay;
  271. end
  272. end
  273. % Check if files exist:
  274. if ~exist(FuncOverlay, 'file')
  275. ErrMsg = {'Error: AFNI functional image missing for selected dataset.';
  276. ['- File: ',FuncOverlay]};
  277. msgbox(ErrMsg, 'Error:');
  278. return;
  279. end
  280. if ~exist(AnatUnderlay, 'file')
  281. ErrMsg = {'Error: AFNI anatomical image missing for selected dataset.';
  282. ['- File: ',AnatUnderlay]};
  283. msgbox(ErrMsg, 'Error:');
  284. return;
  285. end
  286. % Set overlay and underlay files:
  287. [~, Name, Ext] = fileparts(FuncOverlay);
  288. handles.gui.FuncDisplayPath = ...
  289. ['../',handles.name.GroupID{g},'/',handles.name.CondID{c},'/',Name,Ext];
  290. handles.gui.FuncOverlayFile = FuncOverlay;
  291. handles.gui.AnatUnderlayFile = AnatUnderlay;
  292. set(handles.TextboxFuncImageFile, 'String', handles.gui.FuncDisplayPath);
  293. % Set temp viewing folder:
  294. if get(handles.ButtonViewRawSources, 'Value') == 1
  295. handles.gui.TempViewFolder = [handles.paths.AnalysisID,'/TEMP_VIEWER_FILES/'...
  296. 'RAW_SOURCES/',handles.name.GroupID{g},'/',handles.name.CondID{c}];
  297. elseif get(handles.ButtonViewNormSources, 'Value') == 1
  298. handles.gui.TempViewFolder = [handles.paths.AnalysisID,'/TEMP_VIEWER_FILES/'...
  299. 'NORM_SOURCES/',handles.name.GroupID{g},'/',handles.name.CondID{c}];
  300. end
  301. % Set legend name for FuncOverlay file in TSplot:
  302. if strcmp(handles.gui.PlotGrpAvg, 'yes') && s == length(handles.gui.SubjIDAvgList{g})
  303. SubjNameLeg = 'GrpAvg';
  304. else
  305. SubjNameLeg = handles.name.SubjID{g}{s};
  306. end
  307. switch handles.gui.PlotOverlap
  308. case {'no', 'Both'}
  309. handles.gui.FuncOverlayLegend = ...
  310. [SubjNameLeg,'_',handles.name.CondID{c}];
  311. case 'SubjIDs'
  312. handles.gui.FuncOverlayLegend = SubjNameLeg;
  313. case 'CondIDs'
  314. handles.gui.FuncOverlayLegend = handles.name.CondID{c};
  315. end
  316. % Save handles:
  317. guidata(hObject, handles);
  318. %--- Textbox to display dataset selected as functional overlay. ---%
  319. %------------------------------------------------------------------%
  320. function TextboxFuncImageFile_Callback(hObject, eventdata, handles)
  321. EnteredText = get(handles.TextboxFuncImageFile, 'String');
  322. if ~isequal(EnteredText, handles.gui.FuncDisplayPath)
  323. set(handles.TextboxFuncImageFile, 'String', handles.gui.FuncDisplayPath);
  324. msgbox('Note: Use button to change functional image file.');
  325. end
  326. %--- Compile other timeseries datasets for View4D TSplot: ---%
  327. %------------------------------------------------------------%
  328. function [OtherTSData, OtherLegendData, ErrMsg] = GetOtherTimeseriesData(InputHandles)
  329. handles = InputHandles;
  330. paths = handles.paths;
  331. GroupIndex = get(handles.ListboxGroupID, 'Value');
  332. SubjIndices = get(handles.ListboxSubjID, 'Value');
  333. CondIndices = get(handles.ListboxCondID, 'Value');
  334. DataIndex = 1;
  335. MissingFiles = {};
  336. % Compile input data:
  337. for s = SubjIndices
  338. for c = CondIndices
  339. % Compile other input data for TSplots:
  340. if get(handles.ButtonViewRawSources, 'Value') == 1
  341. OtherTSData{DataIndex} = paths.Afni4DSource{GroupIndex}{s,c};
  342. elseif get(handles.ButtonViewNormSources, 'Value') == 1
  343. if strcmp(handles.gui.PlotGrpAvg, 'yes') && ...
  344. s == length(handles.gui.SubjIDAvgList{GroupIndex})
  345. OtherTSData{DataIndex} = paths.Afni4DGrpAvg{GroupIndex}{c};
  346. else
  347. OtherTSData{DataIndex} = paths.Afni4DNormSource{GroupIndex}{s,c};
  348. end
  349. end
  350. % Compile legend for other input data:
  351. if strcmp(handles.gui.PlotGrpAvg, 'yes') && ...
  352. s == length(handles.gui.SubjIDAvgList{GroupIndex})
  353. SubjNameLeg = 'GrpAvg';
  354. else
  355. SubjNameLeg = handles.name.SubjID{GroupIndex}{s};
  356. end
  357. switch handles.gui.PlotOverlap
  358. case {'no', 'Both'}
  359. OtherLegendData{DataIndex} = ...
  360. [SubjNameLeg,'_',handles.name.CondID{c}];
  361. case 'SubjIDs'
  362. OtherLegendData{DataIndex} = SubjNameLeg;
  363. case 'CondIDs'
  364. OtherLegendData{DataIndex} = handles.name.CondID{c};
  365. end
  366. DataIndex = DataIndex + 1;
  367. end
  368. end
  369. % If functional overlay included, remove from "OtherTSData" list.
  370. % Recall: functional overlay is specified separately in View4D_BRIK function.
  371. if ismember(handles.gui.FuncOverlayFile, OtherTSData)
  372. CheckIndex = find(ismember(OtherTSData, handles.gui.FuncOverlayFile));
  373. if ~isempty(CheckIndex)
  374. OtherTSData(CheckIndex) = [];
  375. OtherLegendData(CheckIndex) = [];
  376. end
  377. end
  378. % Make sure data exists:
  379. for d = 1:length(OtherTSData)
  380. if ~exist(OtherTSData{d}, 'file')
  381. MissingFiles = [MissingFiles; OtherTSData{d}];
  382. end
  383. end
  384. if ~isempty(MissingFiles)
  385. ErrMsg = {'ERROR: Some of the selected dataset(s) could not be found.'};
  386. ErrMsg = [ErrMsg; MissingFiles];
  387. else
  388. ErrMsg = [];
  389. end
  390. %=====================================%
  391. % FUNCTIONS FOR PLOTTING SOURCE DATA: %
  392. %=====================================%
  393. %--- Executes on button press in ButtonTimeLegend. ---%
  394. %-----------------------------------------------------%
  395. function ButtonTimeLegend_Callback(hObject, eventdata, handles)
  396. if isempty(handles.gui.BuilderMat)
  397. msgbox('Warning: Select Builder .mat file first.', 'Warning:');
  398. return;
  399. end
  400. if exist([handles.paths.AnalysisID,'/NiftiAfni4D_TimeLegend.txt'], 'file')
  401. open([handles.paths.AnalysisID,'/NiftiAfni4D_TimeLegend.txt']);
  402. else
  403. msgbox('Error: TimeLegend file could not be found.', 'Error:');
  404. return;
  405. end
  406. %--- Executes when selected object is changed in PanelPlotSources. ---%
  407. %---------------------------------------------------------------------%
  408. function PanelPlotSources_SelectionChangeFcn(hObject, eventdata, handles)
  409. % For raw sources, can only overlay condition voxel timeseries (since non-normalised):
  410. if get(handles.ButtonViewRawSources, 'Value') == 1
  411. set(handles.ListboxSubjID, 'Max', 1); % Disable SubjID multi-selection
  412. set(handles.ListboxCondID, 'Max', 2); % Enable CondID multi-selection
  413. GroupIndex = get(handles.ListboxGroupID, 'Value');
  414. SubjIndices = get(handles.ListboxSubjID, 'Value');
  415. if length(SubjIndices) > 1
  416. set(handles.ListboxSubjID, 'Value', 1);
  417. end
  418. end
  419. % For normalised sources, can overlay both subject & condition voxel timeseries:
  420. if get(handles.ButtonViewNormSources, 'Value') == 1
  421. set(handles.ListboxSubjID, 'Max', 2);
  422. set(handles.ListboxCondID, 'Max', 2);
  423. end
  424. % Reset functional overlay selection:
  425. handles.gui.FuncOverlayFile = [];
  426. handles.gui.FuncOverlayLegend = [];
  427. handles.gui.AnatUnderlayFile = [];
  428. handles.gui.TempViewFolder = [];
  429. handles.gui.FuncDisplayPath = [];
  430. set(handles.TextboxFuncImageFile, 'String', []);
  431. % Update handles:
  432. handles = UpdateNameIDs(handles);
  433. guidata(hObject, handles);
  434. %--- Executes on button press in ButtonViewRawSources.
  435. function ButtonViewRawSources_Callback(hObject, eventdata, handles)
  436. %--- Executes on button press in ButtonViewNormSources.
  437. function ButtonViewNormSources_Callback(hObject, eventdata, handles)
  438. %--- Executes on button press in ButtonView4DBrik. ---%
  439. %-----------------------------------------------------%
  440. function ButtonView4DBrik_Callback(hObject, eventdata, handles)
  441. if isempty(handles.gui.BuilderMat)
  442. msgbox('Warning: Select Builder .mat file first.', 'Warning:');
  443. return;
  444. end
  445. if isempty(handles.gui.FuncOverlayFile)
  446. msgbox('Warning: Select dataset to act as functional overlay.', 'Warning:');
  447. return;
  448. end
  449. if isempty(handles.gui.AnatUnderlayFile)
  450. msgbox('Warning: Anatomical underlay file not selected.', 'Warning:');
  451. return;
  452. end
  453. % Check if paths have spaces in them (AFNI paths cannot support spaces):
  454. CheckSpaces1 = strfind(handles.gui.AnatUnderlayFile, ' ');
  455. CheckSpaces2 = strfind(handles.gui.FuncOverlayFile, ' ');
  456. CheckSpaces3 = strfind(handles.gui.TempViewFolder, ' ');
  457. if ~isempty(CheckSpaces1) || ~isempty(CheckSpaces2) || ~isempty(CheckSpaces3)
  458. msgbox('Error: AFNI fcns cannot read folder & file paths containing spaces.', 'Error:')
  459. return;
  460. end
  461. % Check if file is 4D:
  462. CurrentDir = pwd;
  463. Opt.format = 'vector';
  464. [~, FuncImg, ~, ~] = BrikLoad(handles.gui.FuncOverlayFile, Opt);
  465. if numel(size(FuncImg)) ~= 4
  466. msgbox('Error: Selected file is not 4D file. Use "View in AFNI" instead.');
  467. return;
  468. end
  469. % Create temp viewing directory:
  470. if ~exist(handles.gui.TempViewFolder, 'dir')
  471. status = mkdir(handles.gui.TempViewFolder);
  472. if status == 0
  473. msgbox('Error: Failed to create viewing folder in selected directory.');
  474. return;
  475. end
  476. end
  477. % Get temp file paths:
  478. [~, AnatFile, AnatExt] = fileparts(handles.gui.AnatUnderlayFile);
  479. TempAnatFile = [handles.gui.TempViewFolder,'/',AnatFile,AnatExt];
  480. if exist(TempAnatFile, 'file')
  481. delete(TempAnatFile);
  482. delete([handles.gui.TempViewFolder,'/',AnatFile,'.HEAD']);
  483. end
  484. % Copy anatomy file to temp view folder & resample if needed:
  485. system(['3dcopy ',handles.gui.AnatUnderlayFile,' ',TempAnatFile]);
  486. TempAnatFile = MEGpipeline_AfniResampleAnat(TempAnatFile, handles.gui.FuncOverlayFile);
  487. if isempty(TempAnatFile)
  488. msgbox('Warning: Failed to resample anatomy file.', 'Error:');
  489. end
  490. % Compile other datasets for timeseries plot:
  491. [OtherTSData, OtherLegendData, ErrMsg] = GetOtherTimeseriesData(handles)
  492. if ~isempty(ErrMsg)
  493. msgbox(ErrMsg, 'Error:');
  494. return;
  495. end
  496. % Get full legend data:
  497. FullLegendData = [handles.gui.FuncOverlayLegend; OtherLegendData'];
  498. % Plot data:
  499. View4D_BRIK(TempAnatFile, handles.gui.FuncOverlayFile, OtherTSData, FullLegendData);
  500. %--- Executes on button press in ButtonAFNIViewer. ---%
  501. %-----------------------------------------------------%
  502. function ButtonAFNIViewer_Callback(hObject, eventdata, handles)
  503. if isempty(handles.gui.BuilderMat)
  504. msgbox('Warning: Select Builder .mat file first.', 'Warning:');
  505. return;
  506. end
  507. if isempty(handles.gui.FuncOverlayFile)
  508. msgbox('Warning: Select dataset to act as functional overlay.', 'Warning:');
  509. return;
  510. end
  511. if isempty(handles.gui.AnatUnderlayFile)
  512. msgbox('Warning: Anatomical underlay file not selected.', 'Warning:');
  513. return;
  514. end
  515. % Check if paths have spaces in them (AFNI paths cannot support spaces):
  516. CheckSpaces1 = strfind(handles.gui.AnatUnderlayFile, ' ');
  517. CheckSpaces2 = strfind(handles.gui.FuncOverlayFile, ' ');
  518. CheckSpaces3 = strfind(handles.gui.TempViewFolder, ' ');
  519. if ~isempty(CheckSpaces1) || ~isempty(CheckSpaces2) || ~isempty(CheckSpaces3)
  520. msgbox('Error: AFNI fcns cannot read folder & file paths containing spaces.', 'Error:')
  521. return;
  522. end
  523. % Create temp viewing directory:
  524. if ~exist(handles.gui.TempViewFolder, 'dir')
  525. status = mkdir(handles.gui.TempViewFolder);
  526. if status == 0
  527. msgbox('Error: Failed to create viewing folder in selected directory.');
  528. return;
  529. end
  530. end
  531. % Get temp file paths:
  532. [~, AnatFile, AnatExt] = fileparts(handles.gui.AnatUnderlayFile);
  533. [~, FuncFile, FuncExt] = fileparts(handles.gui.FuncOverlayFile);
  534. TempAnatFile = [handles.gui.TempViewFolder,'/',AnatFile,AnatExt];
  535. TempFuncFile = [handles.gui.TempViewFolder,'/',FuncFile,FuncExt];
  536. if exist(TempAnatFile, 'file')
  537. delete(TempAnatFile);
  538. delete([handles.gui.TempViewFolder,'/',AnatFile,'.HEAD']);
  539. end
  540. if exist(TempFuncFile, 'file')
  541. delete(TempFuncFile);
  542. delete([handles.gui.TempViewFolder,'/',FuncFile,'.HEAD']);
  543. end
  544. % Copy func file to temp view folder & convert to AFNI if needed:
  545. system(['3dcopy ',handles.gui.FuncOverlayFile,' ',TempFuncFile]);
  546. % Copy anatomy file to temp view folder & resample if needed:
  547. % Note: Do not change TempAnatFile to resampled version (want high-res as default input).
  548. system(['3dcopy ',handles.gui.AnatUnderlayFile,' ',TempAnatFile]);
  549. ResampledAnat = MEGpipeline_AfniResampleAnat(TempAnatFile, TempFuncFile);
  550. if isempty(ResampledAnat)
  551. msgbox('Warning: Failed to resample anatomy file.', 'Error:');
  552. end
  553. % Prepare file calls to AFNI:
  554. [~, AnatName, ~] = fileparts(TempAnatFile);
  555. AnatName(end-4:end) = []; % Remove +view label
  556. [~, FuncName, ~] = fileparts(TempFuncFile);
  557. FuncName(end-4:end) = [];
  558. % Set environmental variables:
  559. setenv('AFNI_SLAVE_FUNCTIME', 'YES'); % Locks overlay with time-index (Newer versions).
  560. setenv('AFNI_SLAVE_BUCKETS_TOO', 'YES'); % Locks overlay with time-index (Older versions).
  561. setenv('AFNI_SLAVE_THRTIME', 'YES'); % Locks threshold with time-index (Older versions).
  562. setenv('AFNI_SLAVE_THROLAY', 'OLay'); % Locks threshold with time-index (Newer versions).
  563. setenv('AFNI_LEFT_IS_LEFT', 'YES'); % Sets images to neurological view.
  564. setenv('AFNI_THRESH_AUTO', 'NO'); % Threshold slider does not change automatically.
  565. setenv('AFNI_THRESH_LOCK', 'VALUE');
  566. setenv('AFNI_FLOATSCAN', 'YES');
  567. if strcmp(getenv('AFNI_LEFT_IS_LEFT'), 'NO')
  568. msgbox('NOTE: "AFNI_LEFT_IS_LEFT" env. variable is now set to ''YES''.')
  569. end
  570. % Open AFNI command:
  571. CmdLine = ['afni -com ''' ...
  572. 'OPEN_WINDOW A.axialimage;' ...
  573. ' OPEN_WINDOW A.sagittalimage;' ...
  574. ' OPEN_WINDOW A.coronalimage;' ...
  575. ' SWITCH_UNDERLAY A.',AnatName,';' ... % Underlay .BRIK
  576. ' SWITCH_OVERLAY A.',FuncName,';' ... % Overlay .BRIK
  577. ' SET_SUBBRICKS A 1 1 1;' ... % Sets .BRIK index to 1
  578. ' SET_FUNC_AUTORANGE A.+;' ... % Turns ON autorange
  579. ' REDISPLAY;'' &'];
  580. CurrentDir = pwd;
  581. cd(handles.gui.TempViewFolder);
  582. system(CmdLine);
  583. cd(CurrentDir);
  584. %==============================%
  585. % GUIDE "CREATEFCN" FUNCTIONS: %
  586. %==============================%
  587. % --- Executes during object creation, after setting all properties.
  588. function TextboxBuilderMat_CreateFcn(hObject, eventdata, handles)
  589. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  590. set(hObject,'BackgroundColor','white');
  591. end
  592. % --- Executes during object creation, after setting all properties.
  593. function ListboxGroupID_CreateFcn(hObject, eventdata, handles)
  594. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  595. set(hObject,'BackgroundColor','white');
  596. end
  597. % --- Executes during object creation, after setting all properties.
  598. function ListboxSubjID_CreateFcn(hObject, eventdata, handles)
  599. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  600. set(hObject,'BackgroundColor','white');
  601. end
  602. % --- Executes during object creation, after setting all properties.
  603. function ListboxCondID_CreateFcn(hObject, eventdata, handles)
  604. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  605. set(hObject,'BackgroundColor','white');
  606. end
  607. % --- Executes during object creation, after setting all properties.
  608. function TextboxFuncImageFile_CreateFcn(hObject, eventdata, handles)
  609. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  610. set(hObject,'BackgroundColor','white');
  611. end